﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.Exceptions;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YArchitech.LIB;
using YArchitech.Plumbing.LayReliefOpen;
using YArchitech.Revit;

namespace YArchitech.Plumbing
{
	public class LayReliefOpeningMgr
	{
		public Result Excute(UIDocument uiDoc, ref string message, float size = 0f)
		{
			Document document = uiDoc.Document;
			Selection selection = uiDoc.Selection;
			Transaction transaction = null;
			try
			{
				for (;;)
				{
					try
					{
						try
						{
							FormLayReliefOpening formLayReliefOpening = new FormLayReliefOpening(size);
							DialogResult dialogResult = formLayReliefOpening.ShowDialog();
							if (dialogResult == DialogResult.OK)
							{
								for (;;)
								{
									if (dialogResult == DialogResult.OK)
									{
										FamilyInstance familyInstance = null;
										double num = 0.0;
										string empty = string.Empty;
										transaction = new Transaction(document, "布置泄压口");
										transaction.Start();
										XYZ xyz;
										Wall wall;
										if (formLayReliefOpening.LinkChecked)
										{
											Reference reference = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)5, "请选择墙上的布置位置...");
											Element element = (document.GetElement(reference) as RevitLinkInstance).GetLinkDocument().GetElement(reference.LinkedElementId);
											xyz = reference.GlobalPoint;
											xyz = document.GetLinkedDocument(element.Id).GetPointInLinkDocument(xyz);
											wall = (element as Wall);
										}
										else
										{
											Reference reference2 = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, new YArchitech.Revit.WallFilter(), "请选择墙上的布置位置...");
											Element element2 = document.GetElement(reference2);
											xyz = reference2.GlobalPoint;
											wall = (element2 as Wall);
										}
										if (wall == null)
										{
											YJKMessageBox.Show("请拾取墙体", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
											this.EndTransaction(transaction);
										}
										else if (!this.IsSelectedWall(document, wall, out num, out empty))
										{
											YJKMessageBox.Show(empty, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
											this.EndTransaction(transaction);
										}
										else
										{
											double width = wall.Width;
											Curve curve = (wall.Location as LocationCurve).Curve;
											if (curve is Arc)
											{
												YJKMessageBox.Show("暂不支持弧形墙！", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
												this.EndTransaction(transaction);
											}
											else
											{
												Line line = curve as Line;
												if (null == line)
												{
													YJKMessageBox.Show("未知墙！", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
													this.EndTransaction(transaction);
												}
												else
												{
													YJKLine hyline = new YJKLine(line);
													XYZ project = hyline.GetProject(xyz);
													string familyName = (formLayReliefOpening.SelectedItem.TypeInfo == "自动式") ? "自动泄压阀.rfa" : "机械式开启泄压阀.rfa";
													FamilySymbol familySymbolByName = this.GetFamilySymbolByName(familyName, "ReliefOpening", document, BuiltInCategory.OST_MechanicalEquipment);
													if (familySymbolByName != null && !familySymbolByName.IsActive)
													{
														familySymbolByName.Activate();
													}
													double length = (double)formLayReliefOpening.SelectedItem.Width / 304.8;
													using (LayReliefDrawJin layReliefDrawJin = new LayReliefDrawJin(uiDoc, curve, width, length))
													{
														layReliefDrawJin.StartXYZ = project;
														XYZ endPoint = layReliefDrawJin.GetEndPoint(selection);
														this.getRightDirection(curve.GetEndPoint(0), curve.GetEndPoint(1));
														new YJKLine(YJKRevitTools.SetZToZero(hyline.StartPoint), YJKRevitTools.SetZToZero(hyline.EndPoint)).MakeUnBound();
														YJKRevitTools.SetZToZero(endPoint);
														XYZ vectorDirection = layReliefDrawJin.vectorDirection;
														XYZ xyz2 = project.Add(vectorDirection * width / 2.0);
														familyInstance = document.Create.NewFamilyInstance(xyz2, familySymbolByName, (Autodesk.Revit.DB.Structure.StructuralType)0);
														document.Regenerate();
														XYZ facingOrientation = familyInstance.FacingOrientation;
														double num2 = YJKRevitTools.GetTwoXYVectorAngle(facingOrientation, -1.0 * vectorDirection);
														num2 = num2 * 180.0 / Math.PI;
														YJKRotateFamilyInstance hyrotateFamilyInstance = new YJKRotateFamilyInstance();
														hyrotateFamilyInstance.RotateElem(document, familyInstance, num2);
														facingOrientation = familyInstance.FacingOrientation;
														if (!facingOrientation.IsAlmostEqualTo(-1.0 * vectorDirection, 0.001))
														{
															num2 = YJKRevitTools.GetTwoXYVectorAngle(facingOrientation, -1.0 * vectorDirection);
															num2 = num2 * 180.0 / Math.PI;
															hyrotateFamilyInstance.RotateElem(document, familyInstance, num2);
														}
														document.Regenerate();
													}
													if (familyInstance != null && familySymbolByName != null)
													{
														if (familyInstance.GetParameter("宽度") != null)
														{
															familyInstance.GetParameter("宽度").Set((double)formLayReliefOpening.SelectedItem.Width / 304.8);
														}
														if (familyInstance.GetParameter("高度") != null)
														{
															familyInstance.GetParameter("高度").Set((double)formLayReliefOpening.SelectedItem.Height / 304.8);
														}
														if (familyInstance.GetParameter("泄压面积") != null)
														{
															familyInstance.GetParameter("泄压面积").Set(formLayReliefOpening.SelectedItem.Area);
														}
														if (familyInstance.GetParameter("安装洞口宽") != null)
														{
															familyInstance.GetParameter("安装洞口宽").Set(formLayReliefOpening.SelectedItem.OpeningWidth / 304.8);
														}
														if (familyInstance.GetParameter("安装洞口高") != null)
														{
															familyInstance.GetParameter("安装洞口高").Set(formLayReliefOpening.SelectedItem.OpeningHeight / 304.8);
														}
														if (familyInstance.GetParameter("厚度") != null)
														{
															familyInstance.GetParameter("厚度").Set(width);
														}
														if (familyInstance.GetParameter("偏移量") != null)
														{
															familyInstance.GetParameter("偏移量").Set(num);
														}
														if (familySymbolByName.GetParameter("设备类别") != null)
														{
															familySymbolByName.GetParameter("设备类别").Set(formLayReliefOpening.SelectedItem.TypeInfo);
														}
														if (familySymbolByName.GetParameter("制造商") != null)
														{
															familySymbolByName.GetParameter("制造商").Set(formLayReliefOpening.SelectedItem.Company);
														}
														if (familySymbolByName.GetParameter("型号") != null)
														{
															familySymbolByName.GetParameter("型号").Set(formLayReliefOpening.SelectedItem.Model);
														}
													}
													document.Regenerate();
													transaction.Commit();
												}
											}
										}
									}
									else if (dialogResult == DialogResult.Cancel)
									{
										break;
									}
								}
							}
							else if (dialogResult == DialogResult.Cancel)
							{
								break;
							}
						}
						catch (Autodesk.Revit.Exceptions.OperationCanceledException)
						{
						}
						catch (Exception ex)
						{
							message = ex.Message;
							YJKMessageBox.Show(message, MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
							return Autodesk.Revit.UI.Result.Succeeded;
						}
						continue;
					}
					finally
					{
						this.EndTransaction(transaction);
					}
					break;
				}
			}
			catch (Exception ex2)
			{
				message = ex2.Message;
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private void EndTransaction(Transaction transaction)
		{
			if (transaction != null)
			{
				if ((int)transaction.GetStatus() == 1)
				{
					transaction.Commit();
				}
				if ((int)transaction.GetStatus() != 3 && (int)transaction.GetStatus() != 2)
				{
					transaction.RollBack();
				}
			}
		}

		private XYZ GetLayLocation(FamilyInstance fi, Wall wall, XYZ pickPoint, XYZ facePoint, out XYZ layFaceVector)
		{
			XYZ result = null;
			Curve curve = null;
			Curve curve2 = null;
			layFaceVector = null;
			double num = wall.GetParameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
			int num2 = this.TransferHeight(num * 2.0 / 3.0, 10);
			this.GetWallSide(ref curve, ref curve2, wall);
			if (null == curve || null == curve2)
			{
				return result;
			}
			YJKLine hyline = new YJKLine(curve.GetEndPoint(0), curve.GetEndPoint(1));
			hyline.MakeUnBound();
			YJKLine hyline2 = new YJKLine(curve2.GetEndPoint(0), curve2.GetEndPoint(1));
			hyline2.MakeUnBound();
			XYZ project = hyline.GetProject(facePoint);
			XYZ project2 = hyline2.GetProject(facePoint);
			if (project == null || project2 == null)
			{
				return result;
			}
			layFaceVector = facePoint.Subtract(project).Normalize();
			XYZ project3 = ((facePoint.DistanceTo(project) > facePoint.DistanceTo(project2)) ? hyline2 : hyline).GetProject(pickPoint);
			if (project3 == null)
			{
				return result;
			}
			double num3 = fi.GetParameter("厚度").AsDouble();
			XYZ xyz = project3 + -layFaceVector * num3;
			return new XYZ(xyz.X, xyz.Y, (double)num2);
		}

		private XYZ GetLayElevation(List<Level> levels, XYZ pickPoint)
		{
			XYZ result = XYZ.Zero;
			double num = 0.0;
			for (int i = 0; i < levels.Count - 1; i++)
			{
				if (pickPoint.Z > levels[i].Elevation && pickPoint.Z < levels[i + 1].Elevation)
				{
					num = (levels[i + 1].Elevation - levels[i].Elevation) * 2.0 / 3.0;
					break;
				}
			}
			if (num != 0.0)
			{
				result = new XYZ(pickPoint.X, pickPoint.Y, num);
			}
			return result;
		}

		private int TransferHeight(double height, int factor = 10)
		{
			if (height == 0.0)
			{
				return 0;
			}
			int num = (int)Math.Ceiling(Math.Round(height));
			int result;
			if (num % 10 == 0)
			{
				result = num;
			}
			else if (num < 0)
			{
				result = num - num % 10;
			}
			else
			{
				result = num - num % 10 + 10;
			}
			return result;
		}

		public FamilySymbol GetFamilySymbolByName(string familyName, string typeName, Autodesk.Revit.DB.Document doc, BuiltInCategory builtInCategory)
		{
			FamilySymbol familySymbol = null;
			string text = Path.Combine(Product.FamilyLocation, RevitVersion.Version, typeName, familyName);
			Family family = null;
			SubTransaction subTransaction = null;
			try
			{
				List<Element> elementByCategory = YJKElementFilter.GetElementByCategory(doc, typeof(FamilySymbol), builtInCategory);
				YJKRevitTools.GetFamilySymbol(familyName, doc);
				if (elementByCategory != null && elementByCategory.Count > 0)
				{
					foreach (Element element in elementByCategory)
					{
						if ((element as FamilySymbol).GetFamilyNameBySymbol() == familyName.Substring(0, familyName.IndexOf(".")))
						{
							FamilySymbol result;
							familySymbol = (result = (element as FamilySymbol));
							return result;
						}
					}
				}
				if (familySymbol == null)
				{
					subTransaction = new SubTransaction(doc);
					subTransaction.Start();
					if (File.Exists(text))
					{
						doc.LoadFamily(text, out family);
						subTransaction.Commit();
					}
					else
					{
						YJKMessageBox.Show("该族不存在！");
					}
				}
			}
			catch (Exception ex)
			{
				string message = ex.Message;
				YJKMessageBox.Show("加载族失败！");
			}
			finally
			{
				if (subTransaction != null && (int)subTransaction.Commit() != 3)
				{
					subTransaction.RollBack();
				}
			}
			if (family != null)
			{
				using (List<FamilySymbol>.Enumerator enumerator2 = family.GetSymbols().GetEnumerator())
				{
					if (enumerator2.MoveNext())
					{
						familySymbol = enumerator2.Current;
					}
				}
			}
			return familySymbol;
		}

		private bool IsSelectedWall(Autodesk.Revit.DB.Document doc, Wall wall, out double layWallHeight, out string msg)
		{
			layWallHeight = 0.0;
			msg = string.Empty;
			double num = 0.0;
			ElementId elementId = wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT).AsElementId();
			if (null == elementId)
			{
				msg = "所选择的墙不在当前楼层中！";
				return false;
			}
			Element element = wall.Document.GetElement(elementId);
			if (element.GetParameter("立面") != null)
			{
				num = element.GetParameter("立面").AsDouble();
			}
			double num2 = wall.GetParameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble();
			double num3 = num + num2;
			double num4 = wall.GetParameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble();
			wall.GetParameter(BuiltInParameter.WALL_TOP_OFFSET).AsDouble();
			double num5 = num3 + num4;
			if (num5 <= num3)
			{
				msg = "所选择的墙有误！";
				return false;
			}
			double[] viewRange = LayReliefOpeningMgr.GetViewRange(doc.ActiveView);
			if (num3 >= viewRange[0] && num5 <= viewRange[1])
			{
				double num6 = Math.Round((num5 - num3) * 2.0 / 3.0, 3);
				if (num6 < 3.2808398950131235)
				{
					msg = "所选择的墙不适合布置泄压口！";
					return false;
				}
				int num7 = this.TransferHeight((num3 + num6) * 304.8, 10);
				layWallHeight = (double)num7 / 304.8;
				return true;
			}
			else if (num3 >= viewRange[0] && num3 < viewRange[1] && num5 > viewRange[1])
			{
				double num8 = Math.Round((viewRange[1] - num3) * 2.0 / 3.0, 3);
				if (num8 < 3.2808398950131235)
				{
					msg = "所选择的墙不适合布置泄压口！";
					return false;
				}
				int num9 = this.TransferHeight((num3 + num8) * 304.8, 10);
				layWallHeight = (double)num9 / 304.8;
				return true;
			}
			else if (num3 < viewRange[0] && num5 >= viewRange[1])
			{
				double num10 = Math.Round((viewRange[1] - viewRange[0]) * 2.0 / 3.0, 3);
				if (num10 < 3.2808398950131235)
				{
					msg = "所选择的墙不适合布置泄压口！";
					return false;
				}
				int num11 = this.TransferHeight((viewRange[0] + num10) * 304.8, 10);
				layWallHeight = (double)num11 / 304.8;
				return true;
			}
			else
			{
				if (num3 >= viewRange[0] || num5 > viewRange[1] || num5 <= viewRange[0])
				{
					msg = "所选择的墙不在当前楼层中！";
					return false;
				}
				double num12 = Math.Round((num5 - viewRange[0]) * 2.0 / 3.0, 3);
				if (num12 < 3.2808398950131235)
				{
					msg = "所选择的墙不适合布置泄压口！";
					return false;
				}
				int num13 = this.TransferHeight((viewRange[0] + num12) * 304.8, 10);
				layWallHeight = (double)num13 / 304.8;
				return true;
			}
		}

		public static double[] GetViewRange(Autodesk.Revit.DB.View view)
		{
			if (!(view is ViewPlan))
			{
				return null;
			}
			Document document = view.Document;
			double[] array = new double[2];
			if (view.GenLevel.GetParameter("立面") != null)
			{
				Parameter parameter = view.GenLevel.GetParameter("立面");
				array[0] = parameter.AsDouble();
			}
			IEnumerable<Element> enumerable = new HYSystemElementFilter(document).GetElementsByBICategory(BuiltInCategory.OST_Levels).ToList<Element>();
			SortedSet<double> sortedSet = new SortedSet<double>();
			foreach (Element element in enumerable)
			{
				if (element is Level && element.GetParameter("立面") != null)
				{
					Parameter parameter2 = element.GetParameter("立面");
					sortedSet.Add(parameter2.AsDouble());
				}
			}
			bool flag = false;
			foreach (double num in sortedSet)
			{
				if (flag)
				{
					array[1] = num;
					break;
				}
				if (num == array[0])
				{
					flag = true;
				}
			}
			if (array[1] <= array[0])
			{
				array[1] = array[0] + 9.84251968503937;
			}
			return array;
		}

		public List<Level> GetSortLevels(Autodesk.Revit.DB.Document doc)
		{
			List<Level> list = new List<Level>();
			foreach (Element element in new FilteredElementCollector(doc).OfClass(typeof(Level)).ToElements())
			{
				Level item = element as Level;
				list.Add(item);
			}
			return list;
		}

		public bool GetWallSide(ref Curve wallSide1, ref Curve wallSide2, Wall wall)
		{
			Curve curve = (wall.Location as LocationCurve).Curve;
			XYZ endPoint = curve.GetEndPoint(0);
			XYZ endPoint2 = curve.GetEndPoint(1);
			double num = wall.Width / 2.0;
			if (curve as Line != null)
			{
				XYZ xyz = (endPoint - endPoint2).Normalize();
				xyz = xyz.CrossProduct(XYZ.BasisZ);
				wallSide1 = Line.CreateBound(endPoint + xyz * num, endPoint2 + xyz * num);
				wallSide2 = Line.CreateBound(endPoint - xyz * num, endPoint2 - xyz * num);
			}
			else
			{
				Arc arc = curve as Arc;
				XYZ center = arc.Center;
				XYZ xyz2 = this.CalculatMidPoint(endPoint, endPoint2, center, arc.Normal);
				XYZ xyz3 = endPoint - (endPoint - center).Normalize() * num;
				XYZ xyz4 = endPoint2 - (endPoint2 - center).Normalize() * num;
				XYZ xyz5 = xyz2 - (xyz2 - center).Normalize() * num;
				XYZ xyz6 = endPoint + (endPoint - center).Normalize() * num;
				XYZ xyz7 = endPoint2 + (endPoint2 - center).Normalize() * num;
				XYZ xyz8 = xyz2 + (xyz2 - center).Normalize() * num;
				wallSide1 = Arc.Create(xyz3, xyz4, xyz5);
				wallSide2 = Arc.Create(xyz6, xyz7, xyz8);
			}
			return true;
		}

		public XYZ CalculatMidPoint(XYZ ptStart, XYZ ptEnd, XYZ ptCenter, XYZ normal)
		{
			if (normal.Z < 0.0)
			{
				XYZ xyz = ptStart;
				ptStart = ptEnd;
				ptEnd = xyz;
			}
			XYZ xyz2 = ptStart - ptCenter;
			double length = xyz2.GetLength();
			xyz2 = xyz2.Normalize();
			double num = XYZ.BasisX.AngleOnPlaneTo(ptStart - ptCenter, XYZ.BasisZ);
			double num2 = XYZ.BasisX.AngleOnPlaneTo(ptEnd - ptCenter, XYZ.BasisZ);
			if (num > num2)
			{
				num -= Math.PI*2;
			}
			double angle = (num2 - num) / 2.0;
			XYZ xyz3 = this.RotateTo(xyz2, angle, XYZ.BasisZ).Normalize();
			return ptCenter + xyz3 * length;
		}

		public XYZ RotateTo(XYZ pt, double angle, XYZ axis)
		{
			Transform transform = RevitVersionFuncs.CreateRotationAtPoint(axis, angle, new XYZ(0.0, 0.0, 0.0));
			return this.TransformPoint(pt, transform);
		}

		public XYZ TransformPoint(XYZ point, Transform transform)
		{
			double x = point.X;
			double y = point.Y;
			double z = point.Z;
			XYZ xyz = transform.get_Basis(0);
			XYZ xyz2 = transform.get_Basis(1);
			XYZ xyz3 = transform.get_Basis(2);
			XYZ origin = transform.Origin;
			double num = x * xyz.X + y * xyz2.X + z * xyz3.X + origin.X;
			double num2 = x * xyz.Y + y * xyz2.Y + z * xyz3.Y + origin.Y;
			double num3 = x * xyz.Z + y * xyz2.Z + z * xyz3.Z + origin.Z;
			return new XYZ(num, num2, num3);
		}

		private XYZ getRightDirection(XYZ startPoint, XYZ endPoint)
		{
			if ((startPoint - endPoint).X > 0.0)
			{
				return (startPoint - endPoint).Normalize();
			}
			if ((startPoint - endPoint).X != 0.0)
			{
				return -(startPoint - endPoint).Normalize();
			}
			if ((startPoint - endPoint).Y <= 0.0)
			{
				return (endPoint - startPoint).Normalize();
			}
			return (startPoint - endPoint).Normalize();
		}
	}
}
